<template>
  <div class="page-container">
    <div
      v-loading="loading"
      class="content-wrapper"
      :class="{ 'sidebar-open': sidebarVisible && !isTableMode && windowWidth > 768 }"
      :style="transitionStyle"
    >
      <!-- 面包屑 -->
      <el-breadcrumb separator="/" class="breadcrumb">
        <el-breadcrumb-item :to="{ path: '/projects' }">项目管理</el-breadcrumb-item>
      </el-breadcrumb>

      <!-- 头部 -->
      <div class="header">
        <h2>项目管理</h2>
        <div class="controls">
          <!-- *** 修改点：将按钮组替换为下拉框 *** -->
          <el-select
            v-model="currentStatus"
            placeholder="筛选状态"
            clearable
            @change="handleStatusFilterChange"
            class="status-filter-select"
            style="width: 180px; margin-right: 10px"
            size="default"
          >
            <el-option
              v-for="item in statusOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
          <el-button @click="toggleViewMode" class="mode-toggle">
            {{ isTableMode ? '切换到卡片模式' : '切换到表格模式' }}
          </el-button>
          <el-button type="primary" @click="handleAddProject">新增项目</el-button>
        </div>
      </div>
      <!-- 新增：项目名称搜索框 -->
      <div class="filter-section">
        <!-- 移除 :inline="true"，让 flexbox 控制换行 -->
        <el-form class="filter-form">
          <el-form-item label="项目名称" class="filter-item">
            <el-input
              v-model="searchName"
              placeholder="输入项目名称"
              clearable
              @input="handleSearchInput"
              @clear="handleSearchClick"
              style="width: 200px"
            />
          </el-form-item>
          <!-- 将按钮放在独立的 form-item 中，以便通过 CSS 控制位置 -->
          <el-form-item class="filter-item filter-buttons">
            <el-button type="primary" @click="handleSearchClick">查询</el-button>
            <el-button @click="resetProjectFilters">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
      <!-- 卡片模式 -->
      <div v-if="!isTableMode" class="project-cards">
        <el-card
          v-for="project in projects"
          :key="project.id"
          class="project-card animate__animated animate__fadeIn"
          shadow="hover"
          @click="handleViewTasks(project)"
        >
          <div class="card-header">
            <h3 class="project-title" :title="project.name || '未知项目'">
              {{ project.name || '未知项目' }}
            </h3>
            <!-- *** 修改点：使用更新后的 getStatusText/Type *** -->
            <div class="status-and-tasks">
              <el-tag
                :type="getStatusType(project.status)"
                size="small"
                class="status-tag card-status-tag"
              >
                {{ getStatusText(project.status) }}
              </el-tag>
              <!-- *** 新增：显示进行中任务数量 *** -->
              <!-- 判断 activeTasks 是否大于 0 才显示 -->
              <span
                v-if="project.activeTasks > 0 && project.status !== 8"
                class="active-tasks-count"
                title="进行中的任务数量"
              >
                <el-icon><Clock /></el-icon> {{ project.activeTasks }}个任务正在进行
              </span>
              <!-- 如果 activeTasks 为 0 或不存在，可以显示占位符或什么都不显示 -->
              <span
                v-else-if="project.status !== 8"
                class="active-tasks-count inactive"
                title="无进行中的任务"
              >
                <el-icon><Clock /></el-icon> 0
              </span>
            </div>
          </div>

          <el-descriptions :column="1" size="small" class="card-content" border>
            <!-- ... 其他描述项 ... -->
            <el-descriptions-item label="开始时间">{{
              formatTime(project.start_time)
            }}</el-descriptions-item>
            <el-descriptions-item label="截止时间">{{
              formatTime(project.deadline)
            }}</el-descriptions-item>
            <el-descriptions-item label="参与人员">
              <span
                class="ellipsis"
                :title="
                  project.participants && project.participants.length
                    ? project.participants.join(', ')
                    : '-'
                "
              >
                {{
                  project.participants && project.participants.length
                    ? project.participants.join(', ')
                    : '-'
                }}
              </span>
            </el-descriptions-item>
            <el-descriptions-item label="更新于">{{
              formatTime(project.last_update_time)
            }}</el-descriptions-item>
          </el-descriptions>
          <div class="card-actions">
            <!-- ... 操作按钮 ... -->
            <el-button type="text" size="small" @click.stop="showProjectChanges(project)">
              <el-icon><List /></el-icon> 变更记录
            </el-button>
            <el-button type="text" size="small" @click.stop="handleEdit(project)">
              <el-icon><Edit /></el-icon> 编辑
            </el-button>
            <el-button type="text" size="small" @click.stop="showDetails(project)">
              <el-icon><InfoFilled /></el-icon> 查看详情
            </el-button>
            <el-button type="text" size="small" @click.stop="handleAddProgress(project)">
              <el-icon><Plus /></el-icon> 提交进度
            </el-button>
            <el-popconfirm
              title="确定删除此项目吗？"
              confirm-button-text="确定"
              cancel-button-text="取消"
              @confirm="handleDelete(project)"
              popper-class="delete-popover"
            >
              <template #reference>
                <el-button type="text" size="small" class="delete-btn" @click.stop>
                  <el-icon><Delete /></el-icon>
                </el-button>
              </template>
            </el-popconfirm>
          </div>
        </el-card>
        <el-empty
          v-if="!projects.length"
          description="暂无项目数据显示"
          class="empty-state"
        ></el-empty>
      </div>

      <!-- 表格模式 -->
      <div v-if="isTableMode" class="project-table-wrapper">
        <el-table
          :data="projects"
          border
          stripe
          highlight-current-row
          style="
            width: 100%;
            border-radius: 12px;
            box-shadow: 0 4px 24px rgba(0, 0, 0, 0.06);
            overflow: hidden;
          "
          ref="projectTable"
          class="pretty-table"
        >
          <el-table-column prop="name" label="项目名称" width="180">
            <template #default="scope">
              <span class="ellipsis" :title="scope.row.name || '未知项目'">{{
                scope.row.name || '未知项目'
              }}</span>
            </template>
          </el-table-column>
          <el-table-column label="开始时间" width="150">
            <template #default="scope">
              {{ formatTime(scope.row.start_time) }}
            </template>
          </el-table-column>
          <el-table-column label="截止时间" width="150">
            <template #default="scope">
              {{ formatTime(scope.row.deadline) }}
            </template>
          </el-table-column>
          <el-table-column label="参与人员" width="300">
            <template #default="scope">
              <span
                class="ellipsis"
                :title="
                  scope.row.participants && scope.row.participants.length
                    ? scope.row.participants.join(', ')
                    : '-'
                "
              >
                {{
                  scope.row.participants && scope.row.participants.length
                    ? scope.row.participants.join(', ')
                    : '-'
                }}
              </span>
            </template>
          </el-table-column>
          <el-table-column label="状态" width="120" align="center">
            <template #default="scope">
              <el-tag :type="getStatusType(scope.row.status)" size="small">
                {{ getStatusText(scope.row.status) }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column label="进行中的任务" width="120" align="center">
            <template #default="scope">
              <span v-if="scope.row.status !== 8">
                <span :style="{ color: scope.row.activeTasks > 0 ? '#409eff' : '#909399' }">
                  {{ scope.row.activeTasks || 0 }}
                </span>
              </span>
              <span v-else>-</span>
            </template>
          </el-table-column>
          <el-table-column label="操作" align="center" min-width="320" class-name="action-col">
            <template #default="scope">
              <el-button type="primary" size="small" @click="handleViewTasks(scope.row)"
                >任务管理</el-button
              >
              <el-button type="success" size="small" @click="handleEdit(scope.row)" plain
                >编辑</el-button
              >
              <el-button type="info" size="small" @click="showProjectChanges(scope.row)" plain
                >变更记录</el-button
              >
              <el-button type="warning" size="small" @click="showDetails(scope.row)" plain
                >详情</el-button
              >
              <el-button type="primary" size="small" @click="handleAddProgress(scope.row)" plain
                >提交进度</el-button
              >
              <el-popconfirm
                title="确定删除此项目吗？"
                confirm-button-text="确定"
                cancel-button-text="取消"
                @confirm="handleDelete(scope.row)"
                popper-class="delete-popover"
              >
                <template #reference>
                  <el-button type="danger" size="small" plain>
                    <el-icon><Delete /></el-icon> 删除
                  </el-button>
                </template>
              </el-popconfirm>
            </template>
          </el-table-column>
        </el-table>
        <el-empty
          v-if="!projects.length"
          description="暂无项目数据显示"
          class="empty-state pretty-empty"
        ></el-empty>
      </div>

      <!-- 分页 -->
      <el-pagination
        v-if="total > 0"
        v-model:current-page="currentPage"
        v-model:page-size="pageSize"
        :total="total || 0"
        layout="total, sizes, prev, pager, next, jumper"
        :page-sizes="[10, 20, 50, 100]"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        class="pagination"
      />

      <!-- 侧边栏 (变更记录) -->
      <div class="sidebar" :class="{ visible: sidebarVisible && !isTableMode }">
        <div class="sidebar-header">
          <h3>项目变更记录 - {{ currentProjectName || '未选择项目' }}</h3>
          <el-button circle class="close-btn" @click="sidebarVisible = false">
            <el-icon size="16"><Close /></el-icon>
          </el-button>
        </div>
        <div class="sidebar-content">
          <el-form class="filter-form">
            <el-form-item label="时间范围" class="full-width">
              <el-date-picker
                v-model="changesDateRange"
                type="daterange"
                range-separator="至"
                start-placeholder="开始日期"
                end-placeholder="结束日期"
                size="small"
                style="width: 100%"
                @change="fetchChangesSidebar"
              />
            </el-form-item>
            <el-form-item class="button-group">
              <el-button type="primary" size="small" @click="fetchChangesSidebar">查询</el-button>
              <el-button size="small" @click="resetChangesFilters" plain>重置</el-button>
            </el-form-item>
          </el-form>
          <div class="changes-list" v-if="currentProjectId">
            <ul class="timeline">
              <li v-for="(changeGroup, index) in groupedChanges" :key="index" class="timeline-item">
                <div class="timeline-content">
                  <p class="change-description">
                    <el-icon><Clock /></el-icon>
                    <span>
                      {{ changeGroup.operator }} 在
                      {{ formatTimeFull(changeGroup.change_time) }} 进行了以下变更：
                      <ul class="change-details">
                        <li v-for="(change, idx) in changeGroup.changes" :key="idx">
                          {{ change.summary }}
                        </li>
                      </ul>
                    </span>
                  </p>
                </div>
              </li>
            </ul>
          </div>
          <div v-else class="no-selection">
            <p>请选择一个项目以查看变更记录</p>
          </div>
        </div>
      </div>

      <!-- 变更记录弹窗 (表格模式) -->
      <el-dialog
        :title="'项目变更记录 - ' + currentProjectName"
        v-model="changesDialogVisible"
        :width="dialogWidth"
        class="change-log-dialog"
        @close="resetChangesDialog"
        top="5vh"
        v-if="isTableMode"
      >
        <!-- ... 弹窗内容 (表单布局已修改) ... -->
        <el-form class="dialog-filter-form">
          <el-form-item label="时间范围" class="full-width">
            <el-date-picker
              v-model="changesDateRange"
              type="daterange"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              style="width: 100%"
              @change="fetchChangesDialog"
            />
          </el-form-item>
          <el-form-item class="dialog-button-group">
            <div style="display: flex; justify-content: flex-end; gap: 10px; width: 100%">
              <el-button type="primary" @click="fetchChangesDialog">查询</el-button>
              <el-button @click="resetChangesFilters" plain>重置</el-button>
            </div>
          </el-form-item>
        </el-form>
        <div class="changes-list" v-if="dialogGroupedChanges.length">
          <ul class="timeline">
            <li
              v-for="(changeGroup, index) in dialogGroupedChanges"
              :key="index"
              class="timeline-item"
            >
              <div class="timeline-content">
                <p class="change-description">
                  <el-icon><Clock /></el-icon>
                  <span>
                    {{ changeGroup.operator }} 在
                    {{ formatTimeFull(changeGroup.change_time) }} 进行了以下变更：
                    <ul class="change-details">
                      <li v-for="(change, idx) in changeGroup.changes" :key="idx">
                        {{ change.summary }}
                      </li>
                    </ul>
                  </span>
                </p>
              </div>
            </li>
          </ul>
        </div>
        <div v-else class="no-selection">
          <p>暂无变更记录</p>
        </div>
      </el-dialog>

      <!-- 查看详情对话框 -->
      <el-dialog
        title="项目详情"
        v-model="detailsDialogVisible"
        :width="dialogWidth"
        class="details-dialog"
        @close="resetDetailsDialog"
        top="5vh"
      >
        <div class="details-content">
          <!-- ... 其他详情项 ... -->
          <div class="detail-item">
            <span class="label">项目名称：</span>
            <span class="value">{{ currentProjectDetails.name || '未知项目' }}</span>
          </div>
          <div class="detail-item">
            <span class="label">开始时间：</span>
            <span class="value">{{ formatTime(currentProjectDetails.start_time) }}</span>
          </div>
          <div class="detail-item">
            <span class="label">截止时间：</span>
            <span class="value">{{ formatTime(currentProjectDetails.deadline) }}</span>
          </div>
          <div class="detail-item">
            <span class="label">参与人员：</span>
            <span class="value">{{
              currentProjectDetails.participants && currentProjectDetails.participants.length
                ? currentProjectDetails.participants.join(', ')
                : '-'
            }}</span>
          </div>
          <div class="detail-item">
            <span class="label">状态：</span>
            <!-- *** 修改点：使用更新后的 getStatusText/Type *** -->
            <el-tag :type="getStatusType(currentProjectDetails.status)" size="small">{{
              getStatusText(currentProjectDetails.status)
            }}</el-tag>
          </div>
          <!-- ... 其他详情项 ... -->
          <div class="detail-item">
            <span class="label">最后更新：</span>
            <span class="value">{{ formatTime(currentProjectDetails.last_update_time) }}</span>
          </div>
          <div class="detail-item long-text">
            <span class="label">描述：</span>
            <!-- 假设详情页仍显示原始字符串 -->
            <div class="value scrollable">{{ currentProjectDetails.description || '-' }}</div>
          </div>
          <div class="detail-item long-text">
            <span class="label">进度：</span>
            <!-- 假设详情页仍显示原始字符串 -->
            <div class="value scrollable">{{ currentProjectDetails.problem || '-' }}</div>
          </div>
          <div class="detail-item long-text">
            <span class="label">备注：</span>
            <div class="value scrollable">{{ currentProjectDetails.remark || '-' }}</div>
          </div>
          <!-- ... -->
        </div>
      </el-dialog>

      <!-- 编辑/新增对话框 -->
      <el-dialog
        :title="editForm.guid ? '编辑项目' : '新增项目'"
        v-model="editDialogVisible"
        :width="dialogWidth"
        class="edit-dialog"
        @close="resetEditForm"
        top="5vh"
        :close-on-click-modal="false"
      >
        <el-form
          :model="editForm"
          :rules="editRules"
          ref="editFormRef"
          label-width="100px"
          class="edit-form"
          @submit.prevent="submitForm"
        >
          <el-form-item label="项目名称" prop="project_name">
            <el-input v-model="editForm.project_name"></el-input>
          </el-form-item>

          <!-- *** 修改点：项目描述部分 *** -->
          <el-form-item
            v-for="(desc, index) in editForm.descriptions"
            :key="index"
            :label="index === 0 ? '项目描述' : ''"
            :prop="'descriptions.' + index"
            class="description-item"
          >
            <!-- :rules="{ required: index===0, message: '请至少输入第一项描述', trigger: 'blur' }" -->
            <el-input
              v-model="editForm.descriptions[index]"
              type="textarea"
              :rows="2"
              placeholder="请输入描述信息"
              style="width: calc(100% - 40px)"
            ></el-input>
            <el-button
              v-if="editForm.descriptions.length > 1"
              @click="removeDescriptionField(index)"
              text
              circle
              type="danger"
              class="remove-desc-btn"
              title="移除此项描述"
              ><el-icon><Delete /></el-icon
            ></el-button>
          </el-form-item>
          <el-form-item>
            <el-button @click="addDescriptionField" type="primary" link>
              <el-icon><Plus /></el-icon> 增加描述项
            </el-button>
          </el-form-item>
          <!-- *** 结束修改点：项目描述部分 *** -->

          <el-form-item label="备注" prop="remark">
            <el-input v-model="editForm.remark" type="textarea" :rows="2"></el-input>
          </el-form-item>
          <el-form-item label="开始时间" prop="start_time">
            <el-date-picker
              v-model="editForm.start_time"
              type="date"
              placeholder="选择开始日期"
              style="width: 100%"
              value-format="x"
            />
          </el-form-item>
          <el-form-item label="截止时间" prop="deadline">
            <el-date-picker
              v-model="editForm.deadline"
              type="date"
              placeholder="选择截止日期"
              style="width: 100%"
              value-format="x"
            />
          </el-form-item>
          <el-form-item label="参与人员" prop="participants">
            <el-input
              v-model="editForm.participants"
              placeholder="多个人员用英文逗号 , 分隔"
            ></el-input>
          </el-form-item>
          <el-form-item label="状态" prop="status">
            <!-- *** 修改点：更新状态下拉框选项 *** -->
            <el-select
              v-model="editForm.status"
              placeholder="请选择状态"
              style="width: 100%"
              @change="handleStatusChange"
            >
              <el-option
                v-for="item in statusOptions.filter((opt) => opt.value !== null)"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
        </el-form>
        <template #footer>
          <span class="dialog-footer">
            <el-button @click="editDialogVisible = false">取消</el-button>
            <el-button type="primary" @click="submitForm">确定</el-button>
          </span>
        </template>
      </el-dialog>

      <!-- 提交进度对话框 -->
      <el-dialog
        title="提交进度"
        v-model="addProgressDialogVisible"
        :width="dialogWidth"
        class="progress-dialog"
        @close="resetProgressForm"
        top="5vh"
        :close-on-click-modal="false"
      >
        <el-form
          :model="progressForm"
          :rules="progressRules"
          ref="progressFormRef"
          label-width="100px"
          class="edit-form"
          @submit.prevent="submitProgress"
        >
          <el-form-item label="进度描述" prop="new_progress">
            <el-input
              v-model="progressForm.new_progress"
              type="textarea"
              :rows="4"
              placeholder="请输入最新进度"
            ></el-input>
          </el-form-item>
        </el-form>
        <template #footer>
          <span class="dialog-footer">
            <el-button @click="addProgressDialogVisible = false">取消</el-button>
            <el-button type="primary" @click="submitProgress">确定</el-button>
          </span>
        </template>
      </el-dialog>
    </div>
  </div>
</template>

<script>
import { nextTick } from 'vue'; // 引入 Vue 3 Composition API 相关
import dayjs from 'dayjs';
import {
  fetchProjects,
  updateProject,
  fetchChanges,
  createProject,
  deleteProject,
  addProjectProgress,
} from '../api/index';
import {
  List,
  Edit,
  Clock,
  Close,
  InfoFilled,
  Delete,
  Plus,
  Loading,
  Search,
} from '@element-plus/icons-vue'; // 添加 Plus 图标
import { ElMessage, ElMessageBox } from 'element-plus'; // 引入 ElMessage 和 ElMessageBox
import { STATUS_MAP, STATUS_TEXT, STATUS_TYPE } from '@/utils/projectStatus';
import { formatTime, formatTimeFull } from '@/utils/date';
import { validateDateRange, validateDeadlineRequired } from '@/utils/validators';
import _ from 'lodash';

const LOCAL_STORAGE_KEY = 'project_list_filters';

export default {
  components: { List, Edit, Clock, Close, InfoFilled, Delete, Plus, Loading, Search },
  data() {
    return {
      projects: [],
      searchName: '',
      taskDateRange: [],
      total: 0,
      currentPage: 1,
      pageSize: 10,
      loading: false,
      sidebarVisible: false,
      changes: [],
      changesTotal: 0,
      changesDateRange: [],
      currentProjectId: null,
      currentProjectName: '',
      editDialogVisible: false,
      isTableMode: false,
      changesDialogVisible: false,
      dialogChanges: [],
      disableTransition: false,
      currentStatus: null, // 筛选状态，null 表示全部
      detailsDialogVisible: false,
      currentProjectDetails: {},
      debouncedSearch: null,
      editForm: {
        guid: '',
        project_name: '',
        // *** 修改点：将 project_desc 改为 descriptions 数组 ***
        descriptions: [''], // 初始化为一个包含空字符串的数组
        remark: '',
        start_time: null,
        deadline: null,
        participants: '',
        status: STATUS_MAP.PENDING, // 默认状态使用常量
        debouncedSaveFilters: null,
      },
      editRules: {
        project_name: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
        start_time: [
          { required: true, message: '请选择开始时间', trigger: 'change' },
          {
            validator: (rule, value, callback) =>
              validateDateRange(value, this.editForm.deadline, callback),
            trigger: 'change',
          },
        ],
        deadline: [
          {
            validator: (rule, value, callback) =>
              validateDeadlineRequired(
                this.editForm.status,
                value,
                [STATUS_MAP.FINISHED],
                callback,
              ),
            trigger: 'change',
          },
        ],
        status: [{ required: true, message: '请选择状态', trigger: 'change' }],
        participants: [{ required: true, message: '请输入参与人员', trigger: 'blur' }],
      },
      windowWidth: window.innerWidth,
      // *** 新增：用于状态筛选下拉框的选项 ***
      statusOptions: [
        { label: '全部状态', value: null },
        ...Object.entries(STATUS_TEXT).map(([value, label]) => ({
          label,
          value: Number(value),
        })),
      ],
      // 提交进度相关
      addProgressDialogVisible: false,
      progressForm: {
        project_id: '',
        new_progress: '',
      },
      progressRules: {
        new_progress: [{ required: true, message: '请输入进度描述', trigger: 'blur' }],
      },
    };
  },
  computed: {
    transitionStyle() {
      return this.disableTransition ? { transition: 'none' } : {};
    },
    groupedChanges() {
      // 侧边栏变更分组
      return this.groupChanges(this.changes);
    },
    dialogGroupedChanges() {
      // 弹窗变更分组
      return this.groupChanges(this.dialogChanges);
    },
    // *** 新增：计算属性用于响应式弹窗宽度 ***
    dialogWidth() {
      if (this.windowWidth > 1200) {
        return '50%'; // 大屏幕
      } else if (this.windowWidth > 768) {
        return '70%'; // 中等屏幕
      } else {
        return '90%'; // 小屏幕
      }
    },
  },
  created() {
    // *** 新增：添加窗口大小变化监听器 ***
    window.addEventListener('resize', this.handleResize);
    this.debouncedSearch = _.debounce(this.triggerSearch, 500); // 500ms 延迟
  },
  beforeUnmount() {
    // *** 新增：移除监听器 ***
    window.removeEventListener('resize', this.handleResize);
    if (this.debouncedSearch) {
      this.debouncedSearch.cancel(); // 清除防抖计时器
    }
  },
  mounted() {
    this.isRestoringFromRoute = true;
    this.restoreFiltersFromLocalStorage(); // *** 修改点：从本地存储恢复状态 ***
    this.fetchProjects(); // 获取初始数据
    this.handleResize();
    this.$nextTick(() => {
      this.isRestoringFromRoute = false;
    }); // 确保在 fetch 后重置标志
  },
  methods: {
    triggerSearch() {
      console.log('Triggering search for:', this.searchName);
      this.currentPage = 1; // 搜索时重置到第一页
      this.saveFiltersToLocalStorage(); // 保存当前所有状态 (包括 searchName)
      // this.updateRouteQuery();      // 可选：更新路由
      this.fetchProjects(); // 执行后端查询
    },

    // --- 状态恢复与本地存储 ---
    restoreFiltersFromLocalStorage() {
      const savedFilters = localStorage.getItem(LOCAL_STORAGE_KEY);
      if (savedFilters) {
        try {
          const parsedFilters = JSON.parse(savedFilters);
          console.log('Restoring filters from localStorage:', parsedFilters);
          // 恢复状态，注意类型和有效性检查
          const statusValue = parsedFilters.status;
          this.currentStatus = this.statusOptions.some((opt) => opt.value === statusValue)
            ? statusValue
            : null;
          // 恢复名称
          this.searchName = parsedFilters.name || '';
          // 恢复分页，并确保是有效的数字
          this.currentPage =
            Number.isInteger(parsedFilters.page) && parsedFilters.page > 0 ? parsedFilters.page : 1;
          this.pageSize =
            Number.isInteger(parsedFilters.size) && parsedFilters.size > 0
              ? parsedFilters.size
              : 10; // 假设默认10
        } catch (error) {
          console.error('Failed to parse filters from localStorage:', error);
          // 如果解析失败，使用默认值
          this.currentStatus = null;
          this.searchName = '';
          this.currentPage = 1;
          this.pageSize = 10;
          localStorage.removeItem(LOCAL_STORAGE_KEY); // 清除无效数据
        }
      } else {
        // 如果没有保存的筛选，使用默认值
        this.currentStatus = null;
        this.searchName = '';
        this.currentPage = 1;
        this.pageSize = 10;
      }
    },

    saveFiltersToLocalStorage() {
      const filtersToSave = {
        status: this.currentStatus,
        name: this.searchName,
        page: this.currentPage,
        size: this.pageSize,
      };
      console.log('Saving filters to localStorage:', filtersToSave);
      localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(filtersToSave));
    },
    // *** 新增：处理窗口大小变化的方法 ***
    handleResize() {
      this.windowWidth = window.innerWidth;
    },
    handleSizeChange(val) {
      // 每页数量改变
      this.pageSize = val;
      this.currentPage = 1;
      this.saveFiltersToLocalStorage(); // *** 修改点：保存状态 ***
      this.fetchProjects(); // *** 修改点：重新获取数据 ***
    },
    handleCurrentChange(val) {
      // 页码改变
      this.currentPage = val;
      this.saveFiltersToLocalStorage(); // *** 修改点：保存状态 ***
      this.fetchProjects(); // *** 修改点：重新获取数据 ***
    },
    formatTime, // 显式声明方法
    formatTimeFull, // 显式声明方法
    async fetchProjects() {
      this.loading = true;
      // ... (获取项目逻辑基本不变，确保 participants 正确处理) ...
      try {
        const params = {
          page_num: this.currentPage,
          page_size: this.pageSize,
          ...(this.currentStatus !== null && { status: this.currentStatus }),
          ...(this.searchName && { name: this.searchName }),
        };
        // 如果 API 支持:
        // if (this.currentStatus !== null) {
        //   params.status = this.currentStatus;
        // }
        if (this.searchName) {
          params.name = this.searchName; // 假设后端用 name 作为项目名称搜索参数
        }
        const response = await fetchProjects(params);
        if (response.data.status === 200) {
          this.projects =
            response.data.result.data_list.map((project) => ({
              ...project,
              participants: Array.isArray(project.participants)
                ? project.participants
                : project.participants && typeof project.participants === 'string'
                ? project.participants
                    .split(',')
                    .map((p) => p.trim())
                    .filter((p) => p)
                : [],
              // 确保 description 存在，即使为空字符串
              description: project.description || '',
            })) || [];
          this.total = Number(response.data.result.count) || 0;
        } else {
          ElMessage.error('获取项目列表失败: ' + (response?.data.message || '未知错误'));
          this.projects = [];
          this.total = 0;
        }
      } catch (error) {
        console.error('获取项目失败 (Catch):', error);
        ElMessage.error('获取项目失败，请稍后重试');
        this.projects = [];
        this.total = 0;
      } finally {
        this.loading = false;
      }
    },
    resetProjectFilters() {
      // 重置筛选
      this.searchName = '';
      this.currentStatus = null;
      this.currentPage = 1;
      // this.pageSize = 10; // 按需重置
      this.saveFiltersToLocalStorage(); // *** 修改点：保存重置后的状态 ***
      this.fetchProjects(); // *** 修改点：重新获取数据 ***
    },
    // *** 修改点：更新状态文本获取 ***
    getStatusText(status) {
      return STATUS_TEXT[status] !== undefined ? STATUS_TEXT[status] : '未知状态';
    },
    // *** 修改点：更新状态类型获取 ***
    getStatusType(status) {
      return STATUS_TYPE[status] || 'info'; // 默认为 info
    },
    // viewTasks(project) {
    //   this.$router.push({ name: 'Tasks', params: { projectId: project.id } });
    // },

    async handleViewTasks(project) {
      if (!project || !project.id) return;

      this.loading = true; // 开始加载状态（即使是前端判断也很快，但保持一致）

      try {
        const taskCount = project.totalTasks;
        if (taskCount === undefined || taskCount === null) {
          this.$router.push({ name: 'Tasks', params: { projectId: project.id } });
          return;
        }
        if (taskCount > 0) {
          this.$router.push({ name: 'Tasks', params: { projectId: project.id } });
        } else {
          ElMessageBox.confirm(
            `项目 "${project.name || '该项目'}" 当前没有任务，确定要进入任务管理页面吗？`,
            '提示',
            { confirmButtonText: '确定进入', cancelButtonText: '取消', type: 'warning' },
          )
            .then(() => {
              this.$router.push({ name: 'Tasks', params: { projectId: project.id } });
            }) // 只跳转
            .catch(() => {
              ElMessage.info('已取消进入任务管理');
            });
        }
      } catch (error) {
        /* ... */
      } finally {
        this.loading = false;
      }
    },

    // **新增：封装跳转逻辑**
    navigateToTasks(projectId, autoAddTask) {
      const routeParams = { name: 'Tasks', params: { projectId: projectId } };
      if (autoAddTask) {
        routeParams.query = { autoAddTask: 'true' }; // 添加查询参数
      }
      this.$router.push(routeParams);
    },
    // *** 统一显示变更记录入口 ***
    showProjectChanges(project) {
      this.currentProjectId = project.id;
      this.currentProjectName = project.name || '未知项目';
      this.changesDateRange = []; // 打开时重置日期

      if (this.isTableMode) {
        // 表格模式：打开弹窗
        this.dialogChanges = [];
        this.changesDialogVisible = true;
        this.fetchChangesDialog();
      } else {
        // 卡片模式：切换侧边栏
        if (this.sidebarVisible && this.currentProjectId === project.id) {
          this.sidebarVisible = false;
        } else {
          this.changes = [];
          this.sidebarVisible = true;
          this.fetchChangesSidebar();
        }
      }
    },

    async fetchChangesSidebar() {
      // 获取侧边栏数据
      if (!this.currentProjectId) return;
      try {
        const params = {
          obj_id: this.currentProjectId,
          change_time_start:
            this.changesDateRange && this.changesDateRange[0]
              ? dayjs(this.changesDateRange[0]).startOf('day').unix()
              : undefined,
          change_time_end:
            this.changesDateRange && this.changesDateRange[1]
              ? dayjs(this.changesDateRange[1]).endOf('day').unix()
              : undefined,
        };
        Object.keys(params).forEach((key) => params[key] === undefined && delete params[key]);
        const response = await fetchChanges(params); // 使用正确的 API
        if (response.data.status === 200) {
          this.changes = response.data.result.items || [];
          // this.changesTotal = response.result.total || 0; // 如果需要分页
        } else {
          ElMessage.error('获取变更记录(侧边栏)失败: ' + (response?.data.message || '未知错误'));
          this.changes = [];
        }
      } catch (error) {
        console.error('获取变更记录(侧边栏)失败 (Catch):', error);
        ElMessage.error('获取变更记录(侧边栏)时发生网络错误');
        this.changes = [];
      }
    },

    async fetchChangesDialog() {
      // 获取弹窗数据
      if (!this.currentProjectId) return;
      try {
        const params = {
          obj_id: this.currentProjectId,
          change_time_start:
            this.changesDateRange && this.changesDateRange[0]
              ? dayjs(this.changesDateRange[0]).startOf('day').unix()
              : undefined,
          change_time_end:
            this.changesDateRange && this.changesDateRange[1]
              ? dayjs(this.changesDateRange[1]).endOf('day').unix()
              : undefined,
        };
        Object.keys(params).forEach((key) => params[key] === undefined && delete params[key]);
        const response = await fetchChanges(params); // 使用正确的 API
        if (response.data.status === 200) {
          this.dialogChanges = response.data.result.items || [];
        } else {
          ElMessage.error('获取变更记录(弹窗)失败: ' + (response?.data.message || '未知错误'));
          this.dialogChanges = [];
        }
      } catch (error) {
        console.error('获取变更记录(弹窗)失败 (Catch):', error);
        ElMessage.error('获取变更记录(弹窗)时发生网络错误');
        this.dialogChanges = [];
      }
    },

    resetChangesFilters() {
      // 重置变更记录筛选
      this.changesDateRange = [];
      if (this.changesDialogVisible) {
        this.fetchChangesDialog();
      } else if (this.sidebarVisible) {
        this.fetchChangesSidebar();
      }
    },

    resetChangesDialog() {
      // 关闭弹窗时重置
      this.dialogChanges = [];
      this.changesDateRange = [];
      // this.currentProjectId = null; // 按需决定是否重置 ID
      // this.currentProjectName = '';
      // changesDialogVisible 由 v-model 控制
    },

    // --- 提交进度 ---
    handleAddProgress(project) {
      this.resetProgressForm(); // 先重置表单
      this.progressForm.project_id = project.id; // 设置关联的项目 ID
      if (!this.progressForm.project_id) {
        ElMessage.error('无法提交进度：项目 ID 缺失');
        return; // 阻止打开弹窗
      }
      this.addProgressDialogVisible = true;
    },
    resetProgressForm() {
      if (this.$refs.progressFormRef) {
        this.$refs.progressFormRef.resetFields(); // 重置表单项的值和校验状态
        this.$refs.progressFormRef.clearValidate(); // 确保清除校验提示
      }
      this.progressForm = {
        project_id: '', // 通常重置时清空 project_id
        new_progress: '',
      };
    },
    async submitProgress() {
      if (!this.$refs.progressFormRef) return;
      this.$refs.progressFormRef.validate(async (valid) => {
        if (valid) {
          if (!this.progressForm.project_id) {
            ElMessage.error('提交失败：缺少项目 ID');
            return; // 防止提交
          }
          try {
            const params = {
              project_id: this.progressForm.project_id, // 使用项目ID作为任务ID
              new_problem: this.progressForm.new_progress, // 使用进度描述作为问题描述
            };
            // 使用任务的 addProblem API 来提交项目进度
            const response = await addProjectProgress(params);
            if (response.data.status === 200) {
              ElMessage.success('进度添加成功');
              this.addProgressDialogVisible = false;
              // 刷新项目列表
              this.fetchProjects();
            } else {
              ElMessage.error('进度添加失败: ' + (response?.data.message || '未知错误'));
            }
          } catch (error) {
            console.error('添加进度失败:', error);
            ElMessage.error('添加进度时发生网络错误或未知异常');
          }
        } else {
          ElMessage.warning('请检查表单内容是否符合要求');
        }
      });
    },

    toggleViewMode() {
      // 切换视图模式
      this.disableTransition = true;
      this.isTableMode = !this.isTableMode;
      if (this.isTableMode) {
        this.sidebarVisible = false; // 切换到表格时关闭侧边栏
      } else {
        this.changesDialogVisible = false; // 切换到卡片时关闭弹窗
      }
      nextTick(() => {
        setTimeout(() => {
          if (this.isTableMode && this.$refs.projectTable) {
            this.$refs.projectTable.doLayout(); // 重新计算表格布局
          }
          this.disableTransition = false;
        }, 50);
      });
    },

    // 表格模式下显示变更弹窗的入口 (现在统一由 showProjectChanges 处理)
    // showChangesDialog(project) { ... } // 此方法可移除或保留作为别名

    handleEdit(project) {
      // 打开编辑
      this.editForm = {
        guid: project.guid,
        project_name: project.name || '',
        // *** 修改点：处理 description ***
        // 假设 project.description 是单个字符串，转为数组
        descriptions: project.description ? [project.description] : [''], // 如果为空，则提供一个空输入框
        remark: project.remark || '',
        start_time: project.start_time ? project.start_time : null,
        deadline: project.deadline ? project.deadline : null,
        participants: Array.isArray(project.participants) ? project.participants.join(', ') : '',
        status: project.status !== undefined ? project.status : STATUS_MAP.PENDING,
      };
      // 如果 descriptions 数组为空（例如上面转换后 description 本身就是空），确保至少有一个空输入框
      if (this.editForm.descriptions.length === 0) {
        this.editForm.descriptions.push('');
      }
      this.editDialogVisible = true;
      nextTick(() => {
        if (this.$refs.editFormRef) {
          this.$refs.editFormRef.clearValidate(); // 清除可能的旧校验信息
        }
      });
    },

    handleAddProject() {
      // 打开新增
      this.resetEditForm();
      this.editForm.status = STATUS_MAP.PENDING; // 默认状态
      this.editDialogVisible = true;
      nextTick(() => {
        if (this.$refs.editFormRef) {
          this.$refs.editFormRef.clearValidate();
        }
      });
    },

    async handleDelete(project) {
      // 删除项目
      ElMessageBox.confirm(
        `确定要删除项目 "${project.name || '该项目'}" 吗？相关任务将可能受到影响，此操作无法撤销。`,
        '确认删除',
        {
          confirmButtonText: '确定删除',
          cancelButtonText: '取消',
          type: 'warning',
          customClass: 'delete-message-box',
        },
      )
        .then(async () => {
          try {
            const params = { guid: project.guid };
            if (!params.guid) {
              ElMessage.error('无法删除：项目缺少唯一标识符 (guid)');
              return;
            }
            const response = await deleteProject(params);
            if (response.data.status === 200) {
              ElMessage.success(response.data.message || '项目删除成功');
              this.fetchProjects(); // 重新获取列表
            } else {
              ElMessage.error('删除项目失败: ' + (response?.data.message || '未知错误'));
            }
          } catch (error) {
            console.error('删除项目失败 (Catch):', error);
            ElMessage.error('删除项目时发生网络错误');
          }
        })
        .catch(() => {
          ElMessage.info('删除操作已取消');
        });
    },

    resetEditForm() {
      // 重置表单
      if (this.$refs.editFormRef) {
        this.$refs.editFormRef.resetFields();
        this.$refs.editFormRef.clearValidate();
      }
      this.editForm = {
        guid: '',
        project_name: '',
        // *** 修改点：重置 descriptions ***
        descriptions: [''], // 重置为包含一个空字符串的数组
        remark: '',
        start_time: null,
        deadline: null,
        participants: '',
        status: STATUS_MAP.PENDING, // 默认状态
      };
    },

    // *** 新增：添加描述输入框 ***
    addDescriptionField() {
      this.editForm.descriptions.push('');
    },
    // *** 新增：移除描述输入框 ***
    removeDescriptionField(index) {
      // 至少保留一个输入框
      if (this.editForm.descriptions.length > 1) {
        this.editForm.descriptions.splice(index, 1);
      } else {
        ElMessage.warning('至少需要保留一项描述');
      }
    },

    async submitForm() {
      // 提交表单
      if (!this.$refs.editFormRef) return;
      this.$refs.editFormRef.validate(async (valid) => {
        if (valid) {
          // *** 修改点：处理 descriptions ***
          // 1. 过滤掉空描述项
          const nonEmptyDescriptions = this.editForm.descriptions.filter(
            (desc) => desc && desc.trim() !== '',
          );
          // 2. (假设后端需要单个字符串) 将描述数组用换行符合并
          const descriptionString = nonEmptyDescriptions.join('\n');
          // 可选：如果过滤后没有描述了，可以给一个默认值或提示
          // if (nonEmptyDescriptions.length === 0) {
          //   ElMessage.warning('请至少输入一项有效的项目描述');
          //   return; // 如果描述是必需的
          // }
          let action;
          try {
            const params = {
              project_name: this.editForm.project_name,
              // *** 修改点：发送处理后的字符串 ***
              project_desc: descriptionString, // 发送合并后的字符串
              // 如果后端接受数组: project_desc: nonEmptyDescriptions,
              remark: this.editForm.remark,
              start_time: this.editForm.start_time ? dayjs(this.editForm.start_time).unix() : 0,
              deadline: this.editForm.deadline ? dayjs(this.editForm.deadline).unix() : 0,
              participants: this.editForm.participants, // 已经是字符串
              status: this.editForm.status,
            };
            if (params.deadline === 0) {
              delete params.deadline;
            }

            let response;
            action = '新增';
            if (this.editForm.guid) {
              params.guid = this.editForm.guid;
              action = '更新';
              response = await updateProject(params);
            } else {
              response = await createProject(params);
            }
            if (response.data.status === 200) {
              ElMessage.success(response.data.message || `项目${action}成功`);
              this.editDialogVisible = false;
              this.fetchProjects();
            } else {
              ElMessage.error(`项目${action}失败: ` + (response?.data.message || '未知错误'));
            }
          } catch (error) {
            console.error(`项目${action}失败 (Catch):`, error);
            ElMessage.error(`项目${action}时发生网络错误`);
          }
        } else {
          ElMessage.warning('请检查表单内容是否符合要求');
          return false;
        }
      });
    },

    handleStatusFilterChange() {
      this.currentPage = 1; // 筛选变化时重置到第一页
      this.saveFiltersToLocalStorage(); // *** 修改点：保存状态到本地存储 ***
      this.fetchProjects(); // *** 修改点：重新获取数据 ***
    },
    handleSearchInput() {
      // 输入时触发防抖保存和获取
      this.debouncedSearch(); // 调用新的防抖函数
    },
    handleSearchClick() {
      // 点击搜索按钮或清空
      console.log('Search button clicked or input cleared.');
      if (this.debouncedSearch) {
        this.debouncedSearch.cancel(); // 取消可能存在的防抖计时
      }
      this.triggerSearch(); // 立即执行搜索
    },
    triggerSaveAndFetch() {
      // 封装立即触发逻辑
      this.currentPage = 1;
      this.saveFiltersToLocalStorage(); // 保存状态
      this.fetchProjects(); // 获取数据
    },
    // **新增：用于防抖的函数，包含保存和获取**
    debouncedSaveAndFetch() {
      this.currentPage = 1; // 输入搜索时也重置到第一页
      this.debouncedSaveFilters(); // 防抖保存
    },
    showDetails(project) {
      this.currentProjectDetails = { ...project };
      this.detailsDialogVisible = true;
    },

    resetDetailsDialog() {
      // 关闭详情弹窗
      this.currentProjectDetails = {};
      // detailsDialogVisible 由 v-model 控制
    },

    groupChanges(changes) {
      // 分组变更记录 (与 Tasks.vue 相同)
      if (!changes || changes.length === 0) return [];
      const grouped = {};
      changes.forEach((change) => {
        const key = `${change.operator || '未知用户'}-${change.change_time}`;
        if (!grouped[key]) {
          grouped[key] = {
            operator: change.operator || '未知用户',
            change_time: change.change_time,
            changes: [],
          };
        }
        grouped[key].changes.push({ summary: change.summary || '无具体描述' });
      });
      return Object.values(grouped).sort(
        (a, b) =>
          dayjs(Number(b.change_time) * 1000).unix() - dayjs(Number(a.change_time) * 1000).unix(),
      );
    },
    handleStatusChange() {
      // 确保 editFormRef 存在
      if (this.$refs.editFormRef) {
        // 手动触发 deadline 字段的校验
        this.$refs.editFormRef.validateField('deadline', (isValid) => {
          // 这里可以根据需要处理校验结果，通常不需要特别处理，让错误提示自动显示即可
          console.log('Deadline validation triggered by status change:', isValid);
        });
        // 可选：如果开始时间也依赖状态，也可以在这里触发校验
        // this.$refs.editFormRef.validateField('start_time');
      }
    },
  },
};
</script>

<style scoped>
/* --- 通用页面样式 --- */
.page-container {
  position: relative;
  display: flex;
  max-width: 1600px;
  margin: 0 auto;
  padding: 20px;
  overflow-x: hidden;
}

.content-wrapper {
  width: 100%;
  max-width: 100%;
  padding-right: 0;
  transition: margin-left 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* 大屏幕侧边栏打开时 */
.content-wrapper.sidebar-open {
  /* margin-left 由媒体查询控制 */
}

/* --- 面包屑 --- */
.breadcrumb {
  margin-bottom: 20px;
}

/* --- 页面头部 --- */
.header {
  display: flex;
  flex-wrap: wrap;
  gap: 15px;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
}
.header h2 {
  margin: 0;
  color: #303133;
  font-size: 24px;
  white-space: nowrap;
}

/* --- 筛选区域 --- */
.filter-section {
  margin-bottom: 25px;
  padding: 15px 20px;
  background: #f0f2f5; adius: 6px;

  border-radius: 6px;
}

.filter-form {
  display: flex;
  flex-wrap: wrap; er;
  flex
  gap: 15px 20px; 行 */
  gap: 1
  align-items: center;
}

.filter-item {
  margin-bottom: 0; /
  flex: 0 1 auto;
  margin-bottom: 0; ex: 0 1 auto;
}
/* 筛选按钮组推到右侧 */
.filter-buttons {
  /* margin-left: auto; 当空间足够时推到最右 */
  flex-shrink: 0; /* 防止按钮组被压缩 */
}

/* --- 编辑/新增弹窗中的描述项 --- */
.description-item {
  position: relative; /* 为删除按钮定位 */
  margin-bottom: 10px; /* 描述项之间的间距 */
}
.description-item .el-form-item__content {
  /* 覆盖默认样式，让输入框和按钮在同一行 */
  display: flex;
  align-items: center;
  margin-left: 0 !important; /* 如果标签为空，防止左移 */
}

.remove-desc-btn {
  width: 16px; 8px; /* 删除按钮
  height: 16px;
  margin-left: 8px; 紧凑 */
    width:
  padding: 0; /
    height: 16px;
  font-size: 16px;
}

.remove-desc-btn .el-icon,
.el-button--link .el-icon {
  margin-right: 4px;
  font-size: 16px;
  vertical-align: middle;
}

.edit-form .el-button--link {
  /* "增加描述项" 按钮 */
  margin-top: -10px; /* 减少与上方元素的间距 */
  margin-left: 100px; /* 与标签对齐 */
}

/* *** 修改点：头部右侧控件容器 *** */
.controls {
  display: flex;
  flex-wrap: wrap; er;
  gap:
  gap: 10px;
  align-items: center;
}
.status-buttons .el-button {
  padding: 8px 12px;
}
.mode-toggle {
  /* 视图切换按钮 */
  padding: 8px 12px;
}

/* --- 卡片模式 --- */
/* *** 修改点：使用 Grid 布局 *** */
.project-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(380px, 450px));
  gap: 25px;
  margin-bottom: 25px; /* 与分页的间距 */
}

.project-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 20px;
  overflow: hidden;
  background: #ffffff;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.2s ease-in-out;
}

.project-card:hover {
  border-color: #dcdfe6;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08);
  transform: translateY(-4px);
}

.project-card::before {
  /* 顶部装饰线 */
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 4px;
  background: linear-gradient(90deg, #409eff 0%, #67c23a 100%);
  opacity: 0.7;
  content: '';
}

.card-header {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 12px;
}

.card-header {
  display: flex;
  flex-wrap: nowrap; ace-between;
  al
  align-items: flex-start; 对齐 */
  ma
  justify-content: space-between;
  margin-bottom: 12px;
}

.project-title {
  margin: 0;
  font-siz
  flex-grow: 1;
  margin: 0;
  padding-right: 15px; -height: 1.4;
   允许标题增长，但给右侧留出空间 *
  overflow: hidden;
  color: #303133;
  font-weight: 600;
  font-size: 18px;
  line-height: 1.4;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* *** 新增：包裹状态标签和任务数量的容器 *** */
.status-and-tasks {
  display: flex;
  flex-direction: column; /* 垂直排列标签和数量 */
  flex-shrink: 0; x-end; /* 右
  align-items: flex-end;  防止被压缩 */
}

.card-status-tag {
  /* 移除之前的 margin-left (如果存在) */
  margin-bottom: 5px; /* 状态标签和任务数量之间的间距 */
}

/* *** 新增：进行中任务数量的样式 *** */
.active-tasks-count {
  display: inline-flex; olor: #409eff; /* 蓝色，表示进行中 */
  align-items: center;
  padding: 3px 6px;
  color: #409eff; tems: center;

  font-size: 12px;
  line-height: 1; round-color:
  white-space: nowrap;
  padding: 3px
  background-color: #ecf5ff;
    white-spa
  border-radius: 4px;
}
.active-tasks-count .el-icon {
  margin-right: 3px; /* 图标和数字的间距 */
  vertical-align: middle; /* 确保图标垂直居中 */
}
/* 当没有进行中任务时的样式 (可选) */
.active-tasks-count.inactive {
  color: #909399; /* 灰色 */
  background-color: #f4f4f5; /* 浅灰色背景 */
}

.card-content {
  /* el-descriptions */
  flex-grow: 1;
  margin-bottom: 15px;
  font-size: 13px;
}

.project-title {
  flex-grow: 1;
  margin: 0;
  padding-right: 10px;
  overflow: hidden;
  color: #303133;
  font-weight: 600;
  font-size: 18px;
  line-height: 1.4;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* 卡片内状态标签 */
.card-status-tag {
  flex-shrink: 0;
  margin-left: 10px;
}

.card-content {
  /* el-descriptions */
  flex-grow: 1; x;
  margin-
  margin-bottom: 15px;
  font-size: 13px;
}
/* 调整卡片内描述样式 */
.card-content :deep(.el-descriptions__label) {
  width: 70px; /* 标签宽度 */
  padding: 6px 8px !important;
  color: #606266;
  font-size: 13px;
}
.card-content :deep(.el-descriptions__content) {
  padding: 6px 8px !important;
  font-size: 13px;
}
.card-content :deep(.el-descriptions__cell) {
  padding-bottom: 6px !important; /* 单元格底部间距 */
}

.card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: auto; g-top: 10p
  padding-top: 10px;
  border-top: 1px solid #f0f2f5;
}

.card-actions .el-button {
  padding: 4px 8px;
  color: #606266;
  font-size: 13px;
  transition: color 0.2s ease;
}
.card-actions .el-button:hover {
  color: #409eff;
}
.card-actions .delete-btn {
  margin-left: auto; /* 删除按钮靠右 */
  transform: scale(0.8);
  opacity: 0;
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.project-card:hover .delete-btn {
  transform: scale(1);
  opacity: 1;
}
.card-actions .delete-btn:hover {
  color: #f56c6c;
}

/* --- 表格模式 --- */
/* *** 修改点：添加包裹容器用于滚动 *** */
.project-table-wrapper {
  width: 100%;
  margin-bottom: 25px; argin-bottom
  overflow-x: auto;
  background-color: #fff; 5; /* 给包裹
  border: 1px solid #ebeef5; x; /* 圆角 */
  ba
  border-radius: 4px; * 背景色 */
}
.project-table {
  width: 100%;
  min-width: 1200px; /* 根据实际列数调整 */
}
.project-table .link-like {
  /* 使表格中的项目名称可点击 */
  color: #409eff;
  cursor: pointer;
}
.project-table .link-like:hover {
  text-decoration: underline;
}
/* 表格单元格内按钮 */
.project-table :deep(.el-table__cell .cell .el-button) {
  margin: 0 4px;
  padding: 3px 6px;
  font-size: 12px;
}

/* --- 分页 --- */
.pagination {
  display: flex;
  justify-content: flex-end;
  margin-top: 25px;
  padding: 0 5px;
}

/* --- 侧边栏 (变更记录) --- */
.sidebar {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1050;
  display: flex;
  flex-direction: column;
  width: 400px;
  height: 100vh;
  color: #606266;
  background: #fff;
  border-right: 1px solid #e5e7eb;
  transform: translateX(-100%);
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.sidebar.visible {
  box-shadow: 4px 0 12px rgba(0, 0, 0, 0.08);
  transform: translateX(0);
}
.sidebar-header {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: space-between;
  padding: 15px 20px;
  background: #f9fafb;
  border-bottom: 1px solid #e5e7eb;
}
.sidebar-header h3 {
  max-width: calc(100% - 40px);
  margin: 0;
  overflow: hidden;
  font-weight: 600;
  font-size: 16px;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.close-btn {
  /* 关闭按钮 */
  /* position: absolute; top: 10px; right: 10px; */ /* 可选，如果需要绝对定位 */
}
.sidebar-content {
  flex-grow: 1;
  padding: 20px;
  overflow-y: auto;
}
.sidebar-filter-form .el-form-item {
  /* 侧边栏筛选表单项 */
  margin-bottom: 15px;
}
.sidebar-button-group {
  /* 侧边栏筛选按钮组 */
  display: flex;
  justify-content: flex-end; fy-content
  margin-top: 10px;
}

/* --- 变更记录弹窗 (表格模式) --- */
/* 弹窗 body 内边距 */
.change-log-dialog :deep(.el-dialog__body) {
  padding: 15px 25px 25px 25px;
}
/* 弹窗内筛选表单项间距 */
.dialog-filter-form .el-form-item {
  margin-bottom: 15px;
}
/* *** 修改点：弹窗内按钮组容器样式 *** */
.dialog-button-group {
  margin-top: 5px; 
    margin-top
  margin-bottom: 0;
  /* div 内的 flex 布局在 template 中已设置 */
}
/* 弹窗内时间线列表样式 */
.dialog-changes-list {
  max-height: 55vh;
  margin-top: 20px;
  padding-right: 10px;
  overflow-y: auto;
}

/* --- 时间线样式 (共用) --- */
.timeline {
  position: relative;
  margin: 0;
  padding: 0;
  list-style: none;
}
.timeline::before {
  position: absolute;
  top: 5px;
  left: 4px;
  width: 2px;
  height: calc(100% - 5px);
  background: #e5e7eb;
  content: '';
}
.timeline-item {
  position: relative;
  margin-bottom: 18px;
  padding-left: 25px;
}
.timeline-item::before {
  position: absolute;
  top: 5px;
  left: 0px;
  width: 10px;
  height: 10px;
  background: #409eff;
  border: 2px solid #fff;
  border-radius: 50%;
  box-shadow: 0 0 0 1px #409eff;
  content: '';
}
.timeline-content {
  padding: 12px 15px;
  background: #f9fafb;
  border: 1px solid #f0f2f5;
  border-radius: 6px;
}
.change-description {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  margin: 0;
  color: #303133;
  font-size: 13px;
  line-height: 1.5;
  word-break: break-word;
}
.change-description .el-icon {
  margin-top: 2px;
  color: #909399;
}
.change-details {
  margin: 6px 0 0 0;
  padding-left: 20px;
  color: #555;
  font-size: 13px;
  list-style-type: disc;
}
.change-details li {
  margin-bottom: 4px;
}
.no-selection {
  padding: 30px 15px;
  color: #909399;
  font-size: 14px;
  text-align: center;
}

/* --- 详情弹窗 --- */
.details-dialog :deep(.el-dialog__body) {
  padding: 15px 25px 25px 25px;
}
.details-content {
  max-height: 65vh;
  padding-right: 10px;
  overflow-y: auto;
}
.detail-item {
  display: flex;
  align-items: flex-start;
  margin-bottom: 12px;
  font-size: 14px;
}
.detail-item.long-text {
  flex-direction: column;
  align-items: stretch;
}
.detail-item .label {
  flex-shrink: 0;
  min-width: 90px;
  padding-right: 10px;
  color: #555;
  font-weight: 500;
}
.detail-item .value {
  flex-grow: 1;
  color: #303133;
  word-break: break-word;
}
.detail-item .el-tag {
  vertical-align: middle;
} /* 详情里的状态标签 */
.detail-item.long-text .value {
  max-height: 180px;
  margin-top: 4px;
  padding: 10px;
  overflow-y: auto;
  color: #444;
  line-height: 1.6;
  white-space: pre-wrap;
  background: #f9fafb;
  border: 1px solid #e5e7eb;
  border-radius: 4px;
}

/* --- 编辑/新增弹窗 --- */
.edit-dialog :deep(.el-dialog__body) {
  padding: 25px 25px 10px 25px;
}
.edit-form .el-form-item {
  margin-bottom: 18px;
}

/* --- 删除确认 --- */
/* MessageBox 样式 */
.delete-message-box .el-button--primary {
  background-color: #f56c6c;
  border-color: #f56c6c;
}
.delete-message-box .el-button--primary:hover {
  background-color: #f89898;
  border-color: #f89898;
}
/* Popover 样式 */
:deep(.delete-popover) {
  /* 与 Tasks.vue 保持一致 */
}

/* --- 通用工具类 --- */
.ellipsis {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.full-width {
  width: 100%;
}
.scrollable {
  overflow-y: auto;
}
.empty-state {
  /* 空状态提示样式 */
  grid-column: 1 / -1; ding: 40px 0;
     g
  width: 100%;
  padding: 40px 0;
}

/* --- 通用响应式调整 --- */
@media (max-width: 1024px) {
  .project-cards {
    grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
    gap: 20px;
  }
  .project-table {
    min-width: 900px; /* 减小表格最小宽度 */
  }
  /* 调整描述标签宽度 */
  .card-content :deep(.el-descriptions__label) {
    width: 65px;
  }
}

@media (max-width: 768px) {
  .page-container {
    padding: 15px;
  }
  .content-wrapper.sidebar-open {
    margin-left: 0;
  } /* 底部抽屉不推内容 */

  .header {
    flex-direction: column;
    align-items: flex-start;
    margin-bottom: 15px;
  }
  .header h2 {
    margin-bottom: 10px;
    font-size: 20px;
  }
  .controls {
    gap: 8px;
    width: 100%;
  } /* 控件占满宽度 */
  /* 在小屏幕上，让按钮组和单个按钮更好地排列 */
  .controls .el-button-group {
    flex-grow: 1;
  } /* 按钮组占据更多空间 */
  .controls .mode-toggle {
    margin-left: auto;
  } /* 切换按钮推到右侧 */

  .project-cards {
    grid-template-columns: 1fr;
    gap: 15px;
  } /* 单列卡片 */

  /* --- 侧边栏变为底部抽屉 --- */
  .sidebar {
    top: auto;
    bottom: 0;
    z-index: 1100;
    width: 100%;
    height: 60%;
    border-top: 1px solid #e5e7eb;
    border-right: none;
    box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.08);
    transform: translateY(100%);
  }
  .sidebar.visible {
    transform: translateY(0);
  }
  .header .controls {
    gap: 8px;
    width: 100%;
  }
  .controls .status-filter-select {
    flex-grow: 1; /* 让下拉框占据更多空间 */
    min-width: 150px; /* 最小宽度 */
  }
  .controls .mode-toggle {
    margin-left: auto; /* 视图切换按钮靠右 */
  }

  .edit-form .el-button--link {
    /* 调整 "增加描述项" 按钮位置 */
    margin-left: 0;
  }
  .description-item .el-input {
    /* 如果需要在小屏幕调整输入框宽度 */
    width: calc(100% - 40px) !important;
  }
}

/* 大屏幕侧边栏打开时调整内容区域的左边距 */
@media (min-width: 769px) {
  /* 只在大屏幕应用 */
  .content-wrapper.sidebar-open {
    margin-left: 400px; /* 等于侧边栏的宽度 */
    /* 可以 transition，但你已有 transitionStyle */
    /* transition: margin-lef
    width: calc(100% - 400px); 1); */
     width:
    margin-left: 400px; ：如果需要动态计算宽度 */
  }
}
/* ... 其他样式 ... */
.pretty-table .el-table__header th {
  color: #333;
  font-weight: 600;
  font-size: 15px;
  background: #f5f7fa;
  border-bottom: 2px solid #e4e7ed;
}
.pretty-table .el-table__row {
  font-size: 14px;
  transition: background 0.2s;
}
.pretty-table .el-table__row.current-row {
  background: #e6f7ff !important;
}
.pretty-table .el-table__body td {
  border-bottom: 1px solid #f0f0f0;
}
.pretty-table .action-col .el-button {
  margin: 0 2px;
}
.pretty-table .el-tag {
  padding: 2px 10px;
  font-size: 13px;
  border-radius: 6px;
}
.pretty-empty {
  margin-top: 40px;
  color: #aaa;
  font-size: 16px;
}
/* 卡片底部 */
.card-footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px dashed #f0f2f5;
}

.delete-btn {
  color: #f56c6c;
}
</style>
